package com.bstek.uflo.form.view.table;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import com.bstek.dorado.annotation.DataProvider;
import com.bstek.dorado.data.provider.Page;
import com.bstek.dorado.data.type.AggregationDataType;
import com.bstek.dorado.data.type.DataType;
import com.bstek.dorado.data.type.DateDataType;
import com.bstek.dorado.data.type.EntityDataType;
import com.bstek.dorado.data.type.property.BasePropertyDef;
import com.bstek.dorado.data.type.property.Mapping;
import com.bstek.dorado.view.manager.ViewConfig;
import com.bstek.dorado.view.widget.base.SplitPanel;
import com.bstek.dorado.view.widget.grid.DataColumn;
import com.bstek.dorado.view.widget.grid.DataGrid;
import com.bstek.dorado.web.DoradoContext;
import com.bstek.uflo.command.CommandService;
import com.bstek.uflo.form.Constants;
import com.bstek.uflo.form.command.GetTableDefinitionCommand;
import com.bstek.uflo.form.command.QueryDataCommand;
import com.bstek.uflo.form.model.MappingProvider;
import com.bstek.uflo.form.model.MappingSource;
import com.bstek.uflo.form.model.TableColumn;
import com.bstek.uflo.form.model.TableDefinition;
import com.bstek.uflo.form.view.common.FormState;

/**
 * @author Jacky.gao
 * @since 2013年12月2日
 */
@Component("uflo.dataAnalysis")
public class DataAnalysis implements ApplicationContextAware{
	@Autowired
	@Qualifier(CommandService.BEAN_ID)
	private CommandService commandService;
	
	private EntityDataType dataTypeMaster;
	private EntityDataType dataTypeSlave;
	private ApplicationContext applicationContext;
	public void onInit(ViewConfig config) throws Exception{
		HttpServletRequest request=DoradoContext.getCurrent().getRequest();
		String tableId=request.getParameter("id");
		if(StringUtils.isEmpty(tableId)){
			return;
		}
		TableDefinition table=commandService.executeCommand(new GetTableDefinitionCommand(Long.valueOf(tableId)));
		if(table==null){
			throw new IllegalArgumentException("Table "+tableId+" is not exist.");
		}
		dataTypeMaster=(EntityDataType)config.getDataType("dataTypeMaster");
		Map<String,Boolean> mappingMap=new HashMap<String,Boolean>();
		buildDataTypeProperty(config, table,dataTypeMaster,mappingMap);
		if(table.getSlaveTables().size()>0){
			TableDefinition slaveTable=table.getSlaveTables().get(0);
			dataTypeSlave=(EntityDataType)config.getDataType("dataTypeSlave");
			buildDataTypeProperty(config, slaveTable,dataTypeSlave,null);
			BasePropertyDef salveProperty=new BasePropertyDef(Constants.SLAVE_PROPERTY);
			AggregationDataType refDataType=new AggregationDataType();
			refDataType.setId("[dataTypeSlave]");
			refDataType.setElementDataType(dataTypeSlave);
			salveProperty.setDataType(refDataType);
			dataTypeMaster.addPropertyDef(salveProperty);
		}else{
			config.getView().getComponent("dataGridSlave").setIgnored(true);
			SplitPanel splitPanel=(SplitPanel)config.getView().getComponent("splitPanel");
			splitPanel.setPosition("100%");
		}
	}
	
	
	private void buildDataTypeProperty(ViewConfig config, TableDefinition table,EntityDataType dataType,Map<String,Boolean> mappingMap) throws Exception {
		DataGrid grid=null;
		if(mappingMap!=null){
			grid=(DataGrid)config.getView().getComponent("dataGridMaster");			
		}else{
			grid=(DataGrid)config.getView().getComponent("dataGridSlave");						
		}
		BasePropertyDef primaryKeyDef=new BasePropertyDef(Constants.PRIMARY_KEY_COLUMN);
		primaryKeyDef.setDataType(config.getDataType("long"));
		dataType.addPropertyDef(primaryKeyDef);
		for(TableColumn col:table.getColumns()){
			BasePropertyDef def=new BasePropertyDef(col.getName().toLowerCase());
			def.setLabel(col.getMemo());
			DataType dt=getDataType(config,col.getDataType());
			if(dt instanceof DateDataType){
				def.setDisplayFormat("Y-m-d H:i:s");
			}
			def.setDataType(dt);
			def.setDefaultValue(col.getDefaultValue());
			def.setRequired(!col.isEmpty());
			String mappingStr=col.getMapping();
			if(StringUtils.isNotEmpty(mappingStr)){
				def.setMapping(buildMapping(col.getMapping(),col.getMappingSource()));
				if(mappingMap!=null)mappingMap.put(col.getName(), true);
			}else{
				if(mappingMap!=null)mappingMap.put(col.getName(), false);
			}
			dataType.addPropertyDef(def);
			DataColumn datacol=new DataColumn();
			datacol.setName(col.getName().toLowerCase());
			datacol.setProperty(col.getName().toLowerCase());
			grid.addColumn(datacol);
		}
	}
	
	private Mapping buildMapping(String mappingStr,MappingSource mappingSource){
		Mapping mapping=new Mapping();
		mapping.setKeyProperty("key");
		mapping.setValueProperty("label");
		if(mappingSource.equals(MappingSource.MappingProvider)){
			MappingProvider provider=(MappingProvider)applicationContext.getBean(mappingStr);
			mapping.setMapValues(provider.getMapping());
		}else{
			List<Map<String,Object>> list=new ArrayList<Map<String,Object>>();
			for(String pairs:mappingStr.split(";")){
				String[] pair=pairs.split("=");
				if(pair.length==2){
					Map<String,Object> map=new HashMap<String,Object>();
					map.put("key", pair[0]);					
					map.put("label", pair[1]);	
					list.add(map);
				}
			}
			mapping.setMapValues(list);
		}
		
		return mapping;
	}
	
	private DataType getDataType(ViewConfig config,String dataType) throws Exception{
		String type=null;
		dataType=dataType.toLowerCase();
		if(dataType.startsWith("varchar") || dataType.startsWith("nvarchar")){
			type="String";
		}
		if(dataType.startsWith("double")){
			type="double";
		}
		if(dataType.startsWith("float")){
			type="float";
		}
		if(dataType.startsWith("bit")){
			type="boolean";
		}
		if(dataType.startsWith("long")){
			type="long";
		}
		if(dataType.startsWith("date")){
			type="Date";
		}
		if(dataType.startsWith("int") || dataType.startsWith("smallint") || dataType.startsWith("tinyint") || dataType.startsWith("integer")){
			type="int";
		}
		if(dataType.startsWith("number") && dataType.indexOf("(")>-1){
			int start=dataType.indexOf("(")+1;
			int end=dataType.lastIndexOf(")");
			String[] numbers=dataType.substring(start,end).split(",");
			if(numbers.length==1){
				type="long";				
			}else if(Integer.parseInt(numbers[1])>0){
				type="double";								
			}else{
				type="long";				
			}
		}
		if(dataType.startsWith("numeric") && dataType.indexOf("(")>-1){
			int start=dataType.indexOf("(")+1;
			int end=dataType.lastIndexOf(")");
			String[] numbers=dataType.substring(start,end).split(",");
			if(numbers.length==1){
				type="long";				
			}else if(Integer.parseInt(numbers[1])>0){
				type="double";								
			}else{
				type="long";				
			}
		}
		if(type==null){
			throw new IllegalArgumentException("Unsupport datatype:"+dataType+"");
		}
		return config.getDataType(type);
	}
	
	@SuppressWarnings("unchecked")
	@DataProvider
	public void loadData(Page<Map<String,Object>> page,Map<String,Object> parameter){
		String tableId=(String)parameter.get("tableId");
		String state=(String)parameter.get("state");
		Map<String,Object> orders=(Map<String,Object>)parameter.get("orders");
		FormState formState=null;
		if(StringUtils.isNotEmpty(state)){
			formState=FormState.valueOf(state);
		}
		TableDefinition table=commandService.executeCommand(new GetTableDefinitionCommand(Long.valueOf(tableId)));
		commandService.executeCommand(new QueryDataCommand(page,table,formState,orders));
	}
	
	
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext=applicationContext;
	}
}
